package core;

import graphics.Animatable;

import java.awt.Graphics2D;
import java.util.LinkedList;
import java.util.Queue;

import core.behaviors.Behavior;

import util.NameSet;
import util.NamedSet;

abstract public class Actor implements Named<Actor>, Trashable, Animatable {
	
	private String myName;
	
	private String myType;
	
	private boolean trashed;
	
	private NameSet<Behavior> myActions;
	
	private NameSet<NamedSet<Behavior>> myReactions; // notice the interior set is named
	
	private Queue<Behavior> trash_buffer;
	
	public Actor(String name, String type)
	{
		myName = name;
		myType = type;
		trashed = false;
		myActions = new NameSet<Behavior>();
		myReactions = new NameSet<NamedSet<Behavior>>();
		trash_buffer = new LinkedList<Behavior>();
	}
	
	public void assignAction(Behavior b)
	{
		myActions.add(b);
	}
	
	public void removeAction(String b)
	{
		myActions.remove(b);
	}
	
	public void assignReaction(String obstacle, Behavior b)
	{
		NamedSet<Behavior> reactions = myReactions.get(obstacle);
		if (reactions == null)
			reactions = new NamedSet<Behavior>(obstacle);
		reactions.add(b);
		myReactions.add(reactions);
	}
	
	public void removeReaction(String obstacle)
	{
		myReactions.remove(obstacle);
	}
	
	public void removeReaction(String obstacle, String b)
	{
		NamedSet<Behavior> reactions = myReactions.get(obstacle);
		if (reactions == null)
			reactions = new NamedSet<Behavior>(obstacle);
		reactions.remove(b);
		myReactions.add(reactions);
	}

	public String getName() {
		return myName;
	}
	
	public String getType() {
		return myType;
	}
	
	public void setType(String type) {
		myType = type;
	}
	
	public boolean equals(Actor i)
	{
		return myName.equals(i.getName());
	}

	public int compareTo(Actor o) {
		return myName.compareTo(o.getName());
	}

	public boolean isTrashed() {
		return trashed;
	}

	public void trash(boolean jein) {
		trashed = jein;
	}
	
	public void collide(Actor obstacle)
	{
		NamedSet<Behavior> reactions = myReactions.get(obstacle.getType());
		if (reactions == null)
			return;
		for (Behavior current : reactions)
		{
			current.step(this, obstacle);
			if (current.isTrashed())
				trash_buffer.add(current);
		}
		while (trash_buffer.size() > 0)
		{
			myActions.remove(trash_buffer.remove());
		}
	}
	/**
	 * Step through each of the actions once
	 * 
	 * After stepping through the actions check to see whether any of
	 * them have been trashed.  In the event that they have then add
	 * them to the trash buffer and remove them afterwards.
	 */
	public void animate()
	{
		for (Behavior current : myActions)
		{
			current.step(this);
			if (current.isTrashed())
				trash_buffer.add(current);
		}
		while (trash_buffer.size() > 0)
		{
			myActions.remove(trash_buffer.remove());
		}
	}

	abstract public void paint(Graphics2D pen);

}
